﻿using System.Security.Cryptography;

namespace DDD.Domain.Abstract.GuidGenerator
{
    /// <summary>
    /// 前部相同 后部变化
    /// </summary>
    public class SequentialAtEndGuidGenerator : IGuidGenerator
    {
        public Guid Create()
        {
            byte version = (byte)4;
            byte variant = (byte)8;
            byte filterHighBit = 0b00001111;
            byte filterLowBit = 0b11110000;

            var randomBytes = new byte[8];
            RandomNumberGenerator.Create().GetBytes(randomBytes);

            long timestamp = DateTime.UtcNow.Ticks;

            byte[] timestampBytes = BitConverter.GetBytes(timestamp);
            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(timestampBytes);
            }

            byte[] guidBytes = new byte[16];
            // AtEnd: rrrrrrrr-rrrr-Mxdr-Nddd-dddddddddddd
            // Block: 1        2    3    4    5
            // Data4 = Block4 + Block5
            // 排序顺序：Block5 > Block4 > Block3 > Block2 > Block1
            // Data3 = Block3 被认为是 uint16，排序并不是从左到右，为消除影响，x 位取固定值
            Buffer.BlockCopy(randomBytes, 0, guidBytes, 0, 6);
            guidBytes[6] = (byte)(version << 4); // Mx 高4位为版本 | 低4位取：全0
            guidBytes[7] = (byte)(((timestampBytes[7] & filterHighBit) << 4) | (randomBytes[7] & filterHighBit)); ; // dr 高4位为：时间戳[7]低4位 | 低4位取：随机数
            guidBytes[8] = (byte)((variant << 4) | ((timestampBytes[6] & filterLowBit) >> 4)); // Nd 高4位为：变体 | 低4位取：时间戳[6]高4位
            guidBytes[9] = (byte)(((timestampBytes[6] & filterHighBit) << 4) | ((timestampBytes[7] & filterLowBit) >> 4)); // dd 高4位为：时间戳[6]低4位 | 低4位取：时间戳[7]高4位
            Buffer.BlockCopy(timestampBytes, 0, guidBytes, 10, 6); // 时间戳前6个字节

            if (BitConverter.IsLittleEndian)
            {
                Array.Reverse(guidBytes, 6, 2); // 包含版本号的 Data3 块需要翻转
            }

            return new Guid(guidBytes);
        }
    }
}
